/*****************************************************************************\
     Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
                This file is licensed under the Snes9x License.
   For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/

/***********************************************************************************
  SNES9X for Mac OS (c) Copyright John Stiles

  Snes9x for Mac OS X

  (c) Copyright 2001 - 2011  zones
  (c) Copyright 2002 - 2005  107
  (c) Copyright 2002         PB1400c
  (c) Copyright 2004         Alexander and Sander
  (c) Copyright 2004 - 2005  Steven Seeger
  (c) Copyright 2005         Ryan Vogt
  (c) Copyright 2019         Michael Donald Buckley
 ***********************************************************************************/


#include "port.h"
#include "cheats.h"

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include "mac-prefix.h"
#include "mac-dialog.h"
#include "mac-os.h"
#include "mac-stringtools.h"
#include "mac-cheat.h"

#define	kDataBrowser	'BRSR'
#define	kCmCheckBox		'CHK_'
#define	kCmAddress		'ADDR'
#define	kCmValue		'VALU'
#define	kCmDescription	'DESC'
#define	kNewButton		'NEW_'
#define	kDelButton		'DEL_'
#define	kAllButton		'ALL_'

extern SCheatData	Cheat;

typedef struct
{
	uint32	id;
	uint32	address;
	uint8	value;
	bool8	valid;
	bool8	enabled;
	char	description[22];
}	CheatItem;

static WindowRef	wRef;
static HIViewRef	dbRef;
static CheatItem	citem[MAC_MAX_CHEATS];
static uint32		numofcheats;

static void InitCheatItems (void);
static void ImportCheatItems (void);
static void DetachCheatItems (void);
static void AddCheatItem (void);
static void DeleteCheatItem (void);
static void EnableAllCheatItems (void);
static void DBItemNotificationCallBack (HIViewRef, DataBrowserItemID, DataBrowserItemNotification);
static OSStatus CheatEventHandler (EventHandlerCallRef, EventRef, void *);


static void InitCheatItems (void)
{
	for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
	{
		citem[i].id      = i + 1;
		citem[i].valid   = false;
		citem[i].enabled = false;
		citem[i].address = 0;
		citem[i].value   = 0;
		sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
	}
}

static void ImportCheatItems (void)
{
    int cheat_num = std::min((int)Cheat.g.size(), MAC_MAX_CHEATS);
	for (unsigned int i = 0; i < cheat_num; i++)
	{
		citem[i].valid   = true;
		citem[i].enabled = Cheat.g[i].enabled;
		citem[i].address = Cheat.g[i].c[0].address; // mac dialog only supports one cheat per group at the moment
		citem[i].value   = Cheat.g[i].c[0].byte;
		strncpy(citem[i].description, Cheat.g[i].name, 21);
		citem[i].description[21] = '\0';
	}
}

static void DetachCheatItems (void)
{
	S9xDeleteCheats();

	for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
	{
		if (citem[i].valid)
		{
			char code[10];
			snprintf(code, 10, "%x=%x", citem[i].address, citem[i].value);
			int index = S9xAddCheatGroup(citem[i].description, code);
			if(citem[i].enabled && index >= 0)
				S9xEnableCheatGroup(index);
		}
	}
}

void ConfigureCheat (void)
{
	if (!cartOpen)
		return;

//    OSStatus    err;
//    IBNibRef    nibRef;
//
//    err = CreateNibReference(kMacS9XCFString, &nibRef);
//    if (err == noErr)
//    {
//        err = CreateWindowFromNib(nibRef, CFSTR("CheatEntry"), &wRef);
//        if (err == noErr)
//        {
//            DataBrowserCallbacks    callbacks;
//            EventHandlerRef            eref;
//            EventHandlerUPP            eUPP;
//            EventTypeSpec            events[] = { { kEventClassCommand, kEventCommandProcess      },
//                                                 { kEventClassCommand, kEventCommandUpdateStatus },
//                                                 { kEventClassWindow,  kEventWindowClose         } };
//            HIViewRef                ctl, root;
//            HIViewID                cid;
//
//            root = HIViewGetRoot(wRef);
//            cid.id = 0;
//            cid.signature = kDataBrowser;
//            HIViewFindByID(root, cid, &dbRef);
//
//        #ifdef MAC_PANTHER_SUPPORT
//            if (systemVersion < 0x1040)
//            {
//                HISize    minSize;
//                Rect    rct;
//
//                GetWindowBounds(wRef, kWindowContentRgn, &rct);
//                minSize.width  = (float) (rct.right  - rct.left);
//                minSize.height = (float) (rct.bottom - rct.top );
//                err = SetWindowResizeLimits(wRef, &minSize, NULL);
//            }
//        #endif
//
//            callbacks.version = kDataBrowserLatestCallbacks;
//            err = InitDataBrowserCallbacks(&callbacks);
//            callbacks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP(DBClientDataCallback);
//            callbacks.u.v1.itemCompareCallback = NewDataBrowserItemCompareUPP(DBCompareCallBack);
//            callbacks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP(DBItemNotificationCallBack);
//            err = SetDataBrowserCallbacks(dbRef, &callbacks);
//
//            if (systemVersion >= 0x1040)
//                err = DataBrowserChangeAttributes(dbRef, kDataBrowserAttributeListViewAlternatingRowColors, kDataBrowserAttributeNone);
//
//            InitCheatItems();
//            ImportCheatItems();
//
//            DataBrowserItemID    *id;
//
//            id = new DataBrowserItemID[MAC_MAX_CHEATS];
//            if (!id)
//                QuitWithFatalError(@"cheat 01");
//
//            numofcheats = 0;
//
//            for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
//            {
//                if (citem[i].valid)
//                {
//                    id[numofcheats] = citem[i].id;
//                    numofcheats++;
//                }
//            }
//
//            if (numofcheats)
//                err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, numofcheats, id, kDataBrowserItemNoProperty);
//
//            delete [] id;
//
//            cid.signature = kNewButton;
//            HIViewFindByID(root, cid, &ctl);
//            if (numofcheats == MAC_MAX_CHEATS)
//                err = DeactivateControl(ctl);
//            else
//                err = ActivateControl(ctl);
//
//            cid.signature = kAllButton;
//            HIViewFindByID(root, cid, &ctl);
//            if (numofcheats == 0)
//                err = DeactivateControl(ctl);
//            else
//                err = ActivateControl(ctl);
//
//            cid.signature = kDelButton;
//            HIViewFindByID(root, cid, &ctl);
//            err = DeactivateControl(ctl);
//
//            eUPP = NewEventHandlerUPP(CheatEventHandler);
//            err = InstallWindowEventHandler(wRef, eUPP, GetEventTypeCount(events), events, (void *) wRef, &eref);
//
//            err = SetKeyboardFocus(wRef, dbRef, kControlFocusNextPart);
//
//            MoveWindowPosition(wRef, kWindowCheatEntry, true);
//            ShowWindow(wRef);
//            err = RunAppModalLoopForWindow(wRef);
//            HideWindow(wRef);
//            SaveWindowPosition(wRef, kWindowCheatEntry);
//
//            err = RemoveEventHandler(eref);
//            DisposeEventHandlerUPP(eUPP);
//
//            DisposeDataBrowserItemNotificationUPP(callbacks.u.v1.itemNotificationCallback);
//            DisposeDataBrowserItemCompareUPP(callbacks.u.v1.itemCompareCallback);
//            DisposeDataBrowserItemDataUPP(callbacks.u.v1.itemDataCallback);
//
//            CFRelease(wRef);
//
//            DetachCheatItems();
//        }
//
//        DisposeNibReference(nibRef);
//    }
}

static void AddCheatItem (void)
{
//    OSStatus            err;
//    HIViewRef            ctl, root;
//    HIViewID            cid;
//    DataBrowserItemID    id[1];
//    unsigned int        i;
//
//    if (numofcheats == MAC_MAX_CHEATS)
//        return;
//
//    for (i = 0; i < MAC_MAX_CHEATS; i++)
//        if (citem[i].valid == false)
//            break;
//
//    if (i == MAC_MAX_CHEATS)
//        return;
//
//    numofcheats++;
//    citem[i].valid   = true;
//    citem[i].enabled = false;
//    citem[i].address = 0;
//    citem[i].value   = 0;
//    sprintf(citem[i].description, "Cheat %03" PRIu32, citem[i].id);
//
//    id[0] = citem[i].id;
//    err = AddDataBrowserItems(dbRef, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty);
//    err = RevealDataBrowserItem(dbRef, id[0], kCmAddress, true);
//
//    root = HIViewGetRoot(wRef);
//    cid.id = 0;
//
//    if (numofcheats == MAC_MAX_CHEATS)
//    {
//        cid.signature = kNewButton;
//        HIViewFindByID(root, cid, &ctl);
//        err = DeactivateControl(ctl);
//    }
//
//    if (numofcheats)
//    {
//        cid.signature = kAllButton;
//        HIViewFindByID(root, cid, &ctl);
//        err = ActivateControl(ctl);
//    }
}

static void DeleteCheatItem (void)
{
//    OSStatus    err;
//    HIViewRef    ctl, root;
//    HIViewID    cid;
//    Handle        selectedItems;
//    ItemCount    selectionCount;
//
//    selectedItems = NewHandle(0);
//    if (!selectedItems)
//        return;
//
//    err = GetDataBrowserItems(dbRef, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, selectedItems);
//    selectionCount = (GetHandleSize(selectedItems) / sizeof(DataBrowserItemID));
//
//    if (selectionCount == 0)
//    {
//        DisposeHandle(selectedItems);
//        return;
//    }
//
//    err = RemoveDataBrowserItems(dbRef, kDataBrowserNoItem, selectionCount, (DataBrowserItemID *) *selectedItems, kDataBrowserItemNoProperty);
//
//    for (unsigned int i = 0; i < selectionCount; i++)
//    {
//        citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].valid   = false;
//        citem[((DataBrowserItemID *) (*selectedItems))[i] - 1].enabled = false;
//        numofcheats--;
//    }
//
//    DisposeHandle(selectedItems);
//
//    root = HIViewGetRoot(wRef);
//    cid.id = 0;
//
//    if (numofcheats < MAC_MAX_CHEATS)
//    {
//        cid.signature = kNewButton;
//        HIViewFindByID(root, cid, &ctl);
//        err = ActivateControl(ctl);
//    }
//
//    if (numofcheats == 0)
//    {
//        cid.signature = kAllButton;
//        HIViewFindByID(root, cid, &ctl);
//        err = DeactivateControl(ctl);
//    }
}

static void EnableAllCheatItems (void)
{
//    OSStatus    err;
//
//    for (unsigned int i = 0; i < MAC_MAX_CHEATS; i++)
//        if (citem[i].valid)
//            citem[i].enabled = true;
//
//    err = UpdateDataBrowserItems(dbRef, kDataBrowserNoItem, kDataBrowserNoItem, NULL, kDataBrowserItemNoProperty, kCmCheckBox);
}

static OSStatus DBClientDataCallback (HIViewRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue)
{
//    OSStatus     err, result;
//    CFStringRef    str;
//    Boolean        r;
//    uint32        address;
//    uint8        value;
//    char        code[256];
//
//    result = noErr;
//
//    switch (property)
//    {
//        case kCmCheckBox:
//            ThemeButtonValue    buttonValue;
//
//            if (changeValue)
//            {
//                err = GetDataBrowserItemDataButtonValue(itemData, &buttonValue);
//                citem[itemID - 1].enabled = (buttonValue == kThemeButtonOn) ? true : false;
//             }
//            else
//                err = SetDataBrowserItemDataButtonValue(itemData, citem[itemID - 1].enabled ? kThemeButtonOn : kThemeButtonOff);
//
//            break;
//
//        case kCmAddress:
//            if (changeValue)
//            {
//                err = GetDataBrowserItemDataText(itemData, &str);
//                r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
//                CFRelease(str);
//                if (r)
//                {
//                    Boolean    translated;
//
//                    if (S9xProActionReplayToRaw(code, address, value) == NULL)
//                        translated = true;
//                    else
//                    if (S9xGameGenieToRaw(code, address, value) == NULL)
//                        translated = true;
//                    else
//                    {
//                        translated = false;
//                        if (sscanf(code, "%" SCNx32, &address) != 1)
//                            address = 0;
//                        else
//                            address &= 0xFFFFFF;
//                    }
//
//                    citem[itemID - 1].address = address;
//                    sprintf(code, "%06" PRIX32, address);
//                    str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
//                    err = SetDataBrowserItemDataText(itemData, str);
//                    CFRelease(str);
//
//                    if (translated)
//                    {
//                        DataBrowserItemID    id[1];
//
//                        citem[itemID - 1].value = value;
//                        id[0] = itemID;
//                        err = UpdateDataBrowserItems(browser, kDataBrowserNoItem, 1, id, kDataBrowserItemNoProperty, kCmValue);
//                    }
//                }
//            }
//            else
//            {
//                sprintf(code, "%06" PRIX32, citem[itemID - 1].address);
//                str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
//                err = SetDataBrowserItemDataText(itemData, str);
//                CFRelease(str);
//            }
//
//            break;
//
//        case kCmValue:
//            if (changeValue)
//            {
//                err = GetDataBrowserItemDataText(itemData, &str);
//                r = CFStringGetCString(str, code, 256, CFStringGetSystemEncoding());
//                CFRelease(str);
//                if (r)
//                {
//                    uint32    byte;
//
//                    if (sscanf(code, "%" SCNx32, &byte) == 1)
//                        citem[itemID - 1].value = (uint8) byte;
//                    else
//                    {
//                        citem[itemID - 1].value = 0;
//                        err = SetDataBrowserItemDataText(itemData, CFSTR("00"));
//                    }
//                }
//            }
//            else
//            {
//                sprintf(code, "%02" PRIX8, citem[itemID - 1].value);
//                str = CFStringCreateWithCString(kCFAllocatorDefault, code, CFStringGetSystemEncoding());
//                err = SetDataBrowserItemDataText(itemData, str);
//                CFRelease(str);
//            }
//
//            break;
//
//        case kCmDescription:
//            if (changeValue)
//            {
//                code[0] = 0;
//                err = GetDataBrowserItemDataText(itemData, &str);
//                strcpy(code, GetMultiByteCharacters(str, 19));
//                CFRelease(str);
//
//                if (code[0] == 0)
//                {
//                    code[0] = ' ';
//                    code[1] = 0;
//                }
//
//                strcpy(citem[itemID - 1].description, code);
//            }
//            else
//            {
//                str = CFStringCreateWithCString(kCFAllocatorDefault, citem[itemID - 1].description, CFStringGetSystemEncoding());
//                err = SetDataBrowserItemDataText(itemData, str);
//                CFRelease(str);
//            }
//
//            break;
//
//        case kDataBrowserItemIsActiveProperty:
//            err = SetDataBrowserItemDataBooleanValue(itemData, true);
//            break;
//
//        case kDataBrowserItemIsEditableProperty:
//            err = SetDataBrowserItemDataBooleanValue(itemData, true);
//            break;
//
//        default:
//            result = errDataBrowserPropertyNotSupported;
//    }
//
//    return (result);
    return 0;
}


static OSStatus CheatEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
{
//    OSStatus    err, result = eventNotHandledErr;
//    WindowRef    tWindowRef;
//
//    tWindowRef = (WindowRef) inUserData;
//
//    switch (GetEventClass(inEvent))
//    {
//        case kEventClassWindow:
//            switch (GetEventKind(inEvent))
//            {
//                case kEventWindowClose:
//                    QuitAppModalLoopForWindow(tWindowRef);
//                    result = noErr;
//                    break;
//            }
//
//            break;
//
//        case kEventClassCommand:
//            switch (GetEventKind(inEvent))
//            {
//                HICommand    tHICommand;
//
//                case kEventCommandUpdateStatus:
//                    err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
//                    if (err == noErr && tHICommand.commandID == 'clos')
//                    {
//                        UpdateMenuCommandStatus(true);
//                        result = noErr;
//                    }
//
//                    break;
//
//                case kEventCommandProcess:
//                    err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
//                    if (err == noErr)
//                    {
//                        switch (tHICommand.commandID)
//                        {
//                            case kNewButton:
//                                AddCheatItem();
//                                result = noErr;
//                                break;
//
//                            case kDelButton:
//                                DeleteCheatItem();
//                                result = noErr;
//                                break;
//
//                            case kAllButton:
//                                EnableAllCheatItems();
//                                result = noErr;
//                        }
//                    }
//            }
//    }
//
//    return (result);
    return 0;
}
